<?php
/**
 * Created by PhpStorm.
 * User: weiwei
 * Date: 2020-03-20
 * Time: 18:36
 */
namespace service;

use Firebase\JWT\JWT;
use Rych\Random\Random;
use TencentCloud\Cat\V20180409\Models\DescribeTaskDetailRequest;
use TencentCloud\Cme\V20191029\Models\DescribeTasksRequest;
use TencentCloud\Common\Credential;
use TencentCloud\Common\Profile\ClientProfile;
use TencentCloud\Common\Profile\HttpProfile;
use TencentCloud\Common\Exception\TencentCloudSDKException;
use TencentCloud\Vod\V20180717\Models\ModifyMediaInfoRequest;
use TencentCloud\Vod\V20180717\VodClient;
use TencentCloud\Vod\V20180717\Models\DeleteMediaRequest;
use TencentCloud\Vod\V20180717\Models\DescribeMediaInfosRequest;
use TencentCloud\Vod\V20180717\Models\ForbidMediaDistributionRequest;
use TencentCloud\Vod\V20180717\Models\SearchMediaRequest;
use think\facade\Env;
use Vod\Model\VodUploadRequest;
use Vod\VodUploadClient;

/**
 * Class VodServer
 * @package service
 * 本类是腾讯云点播相关操作，本类依赖与tencentcloud/tencentcloud-sdk-php和qcloud/vod-sdk-v5
 * 在使用前确保已安装依赖
 */
class VodServer{
    private static $client = null;
    private static $vodUpload = null;
    private $secretId = '';
    private $secretKey = '';
    private $region = '';
    private $referer_key='';

    /**
     * VodServer constructor.
     * @param null $secretId
     * @param null $secretKey
     * @param null $region
     * @param null $referer_key
     */
    public function __construct($secretId=null,$secretKey=null,$region=null,$referer_key=null){
        $this->secretId = $secretId??Env::get('TENCENT.CLOUD_VOD_ID');
        $this->secretKey = $secretKey??Env::get('TENCENT.CLOUD_VOD_KEY');
        $this->region = $region??'ap-chongqing';
        $this->referer_key = $referer_key??Env::get('TENCENT.REFERER_KEY');
        $cred = new Credential($this->secretId, $this->secretKey);
        $httpProfile = new HttpProfile();
        $httpProfile->setEndpoint("vod.tencentcloudapi.com");
        $clientProfile = new ClientProfile();
        $clientProfile->setHttpProfile($httpProfile);
        self::$client = new VodClient($cred, $region, $clientProfile);
        self::$vodUpload = new VodUploadClient($this->secretId,$this->secretKey);
    }

    /**
     * 上传文件
     * @param string $path_path 待上传的媒体文件路径。必须为本地路径，不支持 URL。
     * @param string $mediaName 上传后的媒体名称，若不填默认采用 MediaFilePath 的文件名。
     * @param null $cover 待上传的封面文件路径。必须为本地路径，不支持 URL。
     * @param null $procedure 上传后需要自动执行的任务流名称
     * @param null $classId 上传的分类
     * @param null $context 来源上下文，用于透传用户请求信息，最长250个字符。
     * @return mixed|string
     */
    public function upload($path_path='',$mediaName='',$cover=null,$procedure=null,$classId=null,$context=null){
        if(!$path_path){
            return '请填写文件';
        }
        if(!is_file($path_path)){
            return '不是一个文件';
        }
        $req = new VodUploadRequest();
        $req->MediaFilePath = $path_path;
        $req->CoverFilePath = $cover??'';
        $req->StorageRegion = $this->region;
        $req->SourceContext = \GuzzleHttp\json_encode($context)??'';
        $req->Procedure = $procedure??'';
        $req->MediaName = $mediaName??'';
        $req->ClassId = $classId??'';
        try {
            $rsp = self::$vodUpload->upload($this->region, $req);
            return \GuzzleHttp\json_decode($rsp->toJsonString(),true);
        } catch (TencentCloudSDKException $e) {
            // 处理上传异常
            return $e;
        }
    }

    /**
     * 获取文件信息
     * @param string $fileId
     * @return array|string
     */
    public function find($fileId=''){
        if(!$fileId){
            return 'FileId不能为空';
        }
        $data = [];
        try {
            $req = new DescribeMediaInfosRequest();
            $params = '{"FileIds":["'.$fileId.'"]}';
            $req->fromJsonString($params);
            $resp = \GuzzleHttp\json_decode(self::$client->DescribeMediaInfos($req)->toJsonString(),true)['MediaInfoSet'];
            if(isset($resp[0])){
               if( isset($resp[0]['BasicInfo']) && isset($resp[0]['MetaData'])){
                   $basicInfo = $resp[0]['BasicInfo'];
                   $metaData = $resp[0]['MetaData'];
                   $data = [
                       'name'=> $basicInfo['Name'],
                       'description'=> $basicInfo['Description'],
                       'createTime'=> strtotime($basicInfo['CreateTime']),
                       'type'=> $basicInfo['Type'],
                       'mediaUrl'=> $basicInfo['MediaUrl'],
                       'fileId'=>$resp[0]['FileId'],
                       'duration'=>duration($metaData['Duration'])
                   ];
               }
            }
            return $data;
        }catch(TencentCloudSDKException $e) {
            return $e;
        }
    }

    /**
     * 删除文件
     * @param string $fileId
     * @return \Exception|mixed|string|TencentCloudSDKException
     */
    public function delete($fileId=''){
        if(!$fileId){
            return 'FileId不能为空';
        }
        try {
            $req = new DeleteMediaRequest();
            $req->deserialize([
                'FileId'=> $fileId
            ]);
//            $params = '{"FileId":"'.$fileId.'"}';
//            $req->fromJsonString($params);
            $resp = self::$client->DeleteMedia($req);
            return \GuzzleHttp\json_decode($resp->toJsonString(), true);
        }catch(TencentCloudSDKException $e) {
            return $e;
        }
    }

    /**
     * @param string $fileId
     * @param string $type
     * @return \Exception|mixed|TencentCloudSDKException
     * forbid：禁播，recover：解禁
     */
    public function forbid($fileId='',$type='forbid'){
        try {
            $req = new ForbidMediaDistributionRequest();
            $params = '{"FileIds":["'.$fileId.'"],"Operation":"'.$type.'"}';
            $req->fromJsonString($params);
            $resp = self::$client->ForbidMediaDistribution($req);
            return \GuzzleHttp\json_decode($resp->toJsonString(), true);
        }
        catch(TencentCloudSDKException $e) {
            return $e;
        }
    }

    /**
     * 修改文件
     * @param string $FileId 媒体文件唯一标识。
     * @param string $Name 媒体文件名称，最长 64 个字符。
     * @param string $Description 媒体文件描述，最长 128 个字符。
     * @param string $ClassId 媒体文件分类 ID。
     * @param string $ExpireTime 媒体文件过期时间，采用 [ISO 日期格式]
     * @param string $coverData 视频封面图片文件（如 jpeg, png 等）进行 [Base64]
     * @return \Exception|mixed|TencentCloudSDKException
     */
    public function upgrade($FileId='',$Name='',$Description='',$ClassId='',$ExpireTime='',$coverData=''){
        try {
            $req = new ModifyMediaInfoRequest();
            $params = '{"FileId":"'.$FileId.'","Name":"'.$Name.'","Description":"'.$Description.'","ClassId":'.$ClassId.',"ExpireTime":"'.$ExpireTime.'","CoverData":"'.$coverData.'"}';
            $req->fromJsonString($params);
            $resp = self::$client->ForbidMediaDistribution($req);
            return \GuzzleHttp\json_decode($resp->toJsonString(), true);
        }
        catch(TencentCloudSDKException $e) {
            return $e;
        }
    }

    /**
     * 查询上传文件
     * @param string $Text 搜索文本，模糊匹配媒体文件名称或描述信息
     * @param array $ClassIds 分类 ID 集合，匹配集合指定 ID 的分类及其所有子类。数组长度限制：10。
     * @param string $StartTime 创建时间的开始时间。大于等于开始时间。格式按照 ISO 8601标准
     * @param string $EndTime 创建时间的结束时间。大于等于开始时间。格式按照 ISO 8601标准
     * @param int $Offset 分页返回的起始偏移量，默认值：0。将返回第 Offset 到第 Offset+Limit-1 条。
     * @param int $Limit 分页返回的记录条数，默认值：10。将返回第 Offset 到第 Offset+Limit-1 条。
     * @param string $Sort 排序方式。Sort.Field 可选值：CreateTime。指定 Text 搜索时，将根据匹配度排序，该字段无效
     * @return \Exception|mixed|TencentCloudSDKException
     */
    public function query($Text='',$ClassIds=[],$StartTime='',$EndTime='',$Offset=0,$Limit=10,$Sort='{"Field":"CreateTime","Order":"desc"}'){
        try {
            $req = new SearchMediaRequest();
            $params = '{"Text":"'.$Text.'","ClassIds":'.$ClassIds.',"StartTime":"'.$StartTime.'","EndTime":"'.$EndTime.'","Sort":'.$Sort.',"Offset":'.$Offset.',"Limit":'.$Limit.'}';
            $req->fromJsonString($params);
            $resp = self::$client->SearchMedia($req);
            return \GuzzleHttp\json_decode($resp->toJsonString(), true);
        }
        catch(TencentCloudSDKException $e) {
            return $e;
        }
    }

    /**
     * 查询任务
     * @param string $TaskId 视频处理任务的任务 ID。
     * @return mixed|string
     */
    public function task($TaskId=''){
        if(!$TaskId){
            return 'TaskId不能为空';
        }
        try {
            $req = new DescribeTaskDetailRequest();
            $params = '{"TaskId":"'.$TaskId.'"}';
            $req->fromJsonString($params);
            $resp = self::$client->DescribeTaskDetail($req);
            return \GuzzleHttp\json_decode($resp->toJsonString(), true);
        }
        catch(TencentCloudSDKException $e) {
            return $e;
        }
    }

    /**
     * 获取任务列表
     * @param string $Status 过滤条件：任务状态，可选值：WAITING（等待中）、PROCESSING（处理中）、FINISH（已完成）。
     * @param string $FileId 过滤条件：文件 ID。
     * @param int $Limit 返回记录条数，默认值：10，最大值：100。
     * @return \Exception|mixed|TencentCloudSDKException
     */
    public function task_list($Status='PROCESSING',$FileId='',$Limit=10){
        try {
            $req = new DescribeTasksRequest();
            $params = '{"Status":"'.$Status.'","FileId":"'.$FileId.'","Limit":'.$Limit.'}';
            $req->fromJsonString($params);
            $resp = self::$client->DescribeTaskDetail($req);
            return \GuzzleHttp\json_decode($resp->toJsonString(), true);
        }
        catch(TencentCloudSDKException $e) {
            return $e;
        }
    }

    /**
     * @param string $appId 账号appId
     * @param string $fieldId 文件ID
     * @param int $exper 试看时长，单位为秒，以十进制表示.如果要指定试看时长，时长必须不小于300秒（即5分钟）
     * @param int $expire 派发签名到期 Unix 时间戳，不填表示签名派发后1天内过期
     * @param string $rlimit 最多允许多少个不同 IP 的终端播放，以十进制表示
     * @param string $us 链接标识，用户增强链接的唯一性
     * @return array
     */
    public function play_signature($appId,$fieldId,$exper=0,$expire=86400,$rlimit='',$us=null): array
    {
        $time = time();
        $_expire = $time + $expire;
        // urlAccessInfo.t 16进制字符串，表示链接的过期时间.具体含义和取值参见
        //  防盗链参数 中的t参数.具体含义和取值参见 防盗链参数 中的t参数
        $urlAccessInfo=[];
        $urlAccessInfo['t'] = strtolower(dechex($_expire));
        if($exper){
            $urlAccessInfo['exper'] = intval($exper);
        }
        if($rlimit){
            $urlAccessInfo['rlimit'] = intval($rlimit);
        }
        $urlAccessInfo['us'] = $us??(new Random())->getRandomString(6);
        $payload = [
            'appId'=>intval($appId),
            'fileId'=>intval($fieldId),
            'currentTimeStamp'=> $time,
            'expireTimeStamp'=> $_expire,
            'urlAccessInfo'=> $urlAccessInfo
        ];
        if(empty($exper)){
            unset($payload['urlAccessInfo']['exper']);
        }
        if(empty($rlimit)){
            unset($payload['urlAccessInfo']['rlimit']);
        }
        $jwt = JWT::encode($payload, $this->referer_key);
        return [
            'payload'=>$payload,
            'token'=>$jwt
        ];
    }

    /**
     * @param string $fileID
     * @param null $t
     * @param null $exper
     * @param null $rlimit
     * @return array
     */
    public function referer_key($fileID='',$t=null,$exper=null,$rlimit=null){
        $result = $this->find($fileID);
        $url = $result['transInfo']['TranscodeSet'][0]['Url'];
        $dir = pathinfo(parse_url($url)['path'])['dirname'];
        $tmp = $this->referer_key.$dir;
        $query = [];
        $t = $t??strtolower(dechex(time()+ 86400));
        $tmp .= $t;
        $query['t'] = $t;
        $us = (new Random())->getRandomString(10,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789');
        if($exper){
            $tmp .= $exper;
            $query['exper'] = $exper;
        }
        if($rlimit){
            $tmp .= $rlimit;
            $query['rlimit'] = $rlimit;
        }
        if($us){
            $tmp .= $us;
            $query['us'] = $us;
        }
        $sign = md5($tmp);
        $query['sign'] = $sign;
        return [
            'trgUrl'=>$url,
            'orgUrl'=>$url . '?' .http_build_query($query)
        ];
    }
}